package winOrDie.Sound.Voice;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.zip.ZipOutputStream;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.TargetDataLine;

import winOrDie.GameEngine.RT.mp.MapBoard;
import winOrDie.Net.Client.WoD_Peer;
import winOrDie.graphics.maps.WoD_Map;


public class WoD_Voice {
	protected boolean running;
	// ByteArrayOutputStream out;
	private DatagramSocket in = null;
	private DatagramSocket out = null;

	private static boolean habla = false;
	
	private InetAddress recvAddress = null;

	private int out_port = -1;
	private int in_port = -1;
	private String out_Address = null;

	private int bufferSize = 160;
	
	private WoD_Voice_Time voiceTime = null;
	
	public int getOut_port() {
		return out_port;
	}

	/**
	 * cierto si habla = true
	 * @return
	 */
	public static boolean berrando(){
		return habla;
	}
	
	/**
	 * permite hablar
	 */
	public static void berra(){
		habla = true;
	}
	
	/**
	 * impide hablar
	 */
	public static void noBerres(){
		habla = false;
	}
	
	public void setOut_port(int outPort) {
		out_port = outPort;
	}

	public int getIn_port() {
		return in_port;
	}

	public void setIn_port(int inPort) {
		in_port = inPort;
	}

	public String getOut_Address() {
		return out_Address;
	}

	public void setOut_Address(String outAddress) {
		out_Address = outAddress;
	}

	public WoD_Voice_Time getVoiceTime() {
		return voiceTime;
	}
	
	public WoD_Voice(ArrayList<WoD_Peer> woDPeers) {
		super();
		voiceTime = new WoD_Voice_Time();
		this.woDPeers = woDPeers;
		// recvAddress = InetAddress.getByName("localhost");
	}

	
	private ArrayList<WoD_Peer> woDPeers = null;
	
	// Describe the audio format in which you want to record the data
	private AudioFormat getFormat() {
		// Here is an example that uses the second constructor to create an
		// AudioFormat object for single channel recording in 8 kHz format:
		float sampleRate = 8000;
		int sampleSizeInBits = 8;
		int channels = 1;
		boolean signed = true;
		boolean bigEndian = true;
		return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed,
				bigEndian);

	}

	

	public void startTest(boolean capture) {
		running = capture;
		playAudio();
		captureAudio();
	}

	public void stopTest() {
		running = false;
	}

	private void playAudio() {
		try {
			in = new DatagramSocket(in_port);

			// byte audio[] = out.toByteArray();
			// InputStream input =
			// new ByteArrayInputStream(audio);
			final AudioFormat format = getFormat();
			// final AudioInputStream ais =
			// new AudioInputStream(input, format,
			// audio.length / format.getFrameSize());
			DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
			final SourceDataLine line = (SourceDataLine) AudioSystem
					.getLine(info);
			line.open(format);
			//System.out.println(line);
			line.start();

			Runnable runner = new Runnable() {
				// int bufferSize = (int) format.getSampleRate() *
				// format.getFrameSize();
				// int bufferSize = 160;

				// byte buffer[] = new byte[bufferSize];

				public void run() {

					try {
						while (running) {
							System.out.println("playplayplayplayplayplayplayplayplayplayplayplayplayplay");
							byte[] rcvb = new byte[900];
							DatagramPacket dp = new DatagramPacket(rcvb,
									rcvb.length);
							
							
							
							MapBoard.woDVoiceTime.entraTiempo(5 * MapBoard.FPS);
							
							
							in.receive(dp);

							byte[] audio = new byte[dp.getLength()];
							byte audio2[];
							// System.out.println("packet received " + audio.length);
							System.arraycopy(rcvb, 0, audio, 0, audio.length);

//							InputStream input = new ByteArrayInputStream(audio);
							
//							System.out.println("decodifica");
							
							
//							System.out.println("entra a decodificar");
////							audio = cds.decode(audio);
//							System.out.println("sale de decodificar");
							
//							final AudioInputStream ais = new AudioInputStream(
//									input, format, audio.length
//										
//									AudioSystem.
//			                        write()									
//									
//									/ format.getFrameSize());
//
//							int count;
//							while ((count = ais.read(buffer, 0, buffer.length)) != -1) {
//								if (count > 0) {
							
							
//							line.write(audio, 0, audio.length);
//							System.out.println(WAC.byteToHex(audio, true));
							if (audio.length >= bufferSize) line.write(audio, 0, audio.length);
							else{
								audio2 = WAC.uncompress(audio);
								line.write(audio2, 0, audio2.length);
							}
									
							// System.out
							// .println("write to line " + count);
//								}
//							}
							//line.drain();
							
								
						}
						line.drain();
						line.close();
					} catch (IOException e) {
						System.err.println("I/O problems: " + e);
						System.exit(-3);
					}
				}
			};
			Thread playThread = new Thread(runner);
			playThread.start();
		} catch (LineUnavailableException e) {
			System.err.println("Line unavailable: " + e);
			System.exit(-4);
		} catch (SocketException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void captureAudio() {
		try {
			final AudioFormat format = getFormat();
			DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
			final TargetDataLine line = (TargetDataLine) AudioSystem
					.getLine(info);
			line.open(format);
			line.start();
			Runnable runner = new Runnable() {
				// int bufferSize = (int) format.getSampleRate()*
				// format.getFrameSize();

				long currentTime;
				
				byte buffer[] = new byte[bufferSize];
				byte buffer2[];

				public void run() {

//					ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
//					DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
//					
//					
//					ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(buffer);
//					DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream);
					
//					int type = dataInputStream.readByte();
					
//					dataOutputStream.writeByte(type);
					
					// System.out.println(format.getFrameSize() + " " + bufferSize);
					// out = new ByteArrayOutputStream();
					try {
						out = new DatagramSocket();
					} catch (SocketException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
					running = true;
					try {
						while (running) {
							currentTime = System.currentTimeMillis();

//							if (habla && MapBoard.woDVoiceTime.ceroOmenos()){
							if (habla){
//								System.out.println("entra");
								int count = line.read(buffer, 0, bufferSize);
								if (count > 0) {
									
									System.out.println("lambdaTIME " +(System.currentTimeMillis() -  currentTime));
									currentTime = System.currentTimeMillis();
									
//									System.out.println("HEX: " + WAC.byteToHex(buffer, true));
//									System.out.println("LHT: " + WAC.byteToHex(WAC.light(buffer), true));
//									System.out.println("COD: " + WAC.byteToHex(WAC.compress(WAC.light(buffer)), true));
//	                                System.out.println("DEC: " + WAC.byteToHex(WAC.uncompress(WAC.compress(WAC.light(buffer))), true));
//	                                System.out.println("");
	                                
									buffer2 = WAC.compress(buffer);
//									buffer2 = WAC.compress(WAC.light(buffer));
//									System.out.println("codifica");
									
							
									
									for (WoD_Peer woDPeer : woDPeers) {
										System.out.println("Enviar paquetes de voz 2222222");

										if (buffer2.length >= buffer.length){
											DatagramPacket dp = new DatagramPacket(buffer,
													buffer.length, InetAddress.getByName(woDPeer.getHostDirection()),
													woDPeer.getVoice_UDP_Port());
											out.send(dp);
											System.out.println(WAC.byteToHex(buffer, true));
										}else{
											DatagramPacket dp = new DatagramPacket(buffer2,
													buffer2.length, InetAddress.getByName(woDPeer.getHostDirection()),
													woDPeer.getVoice_UDP_Port());
											out.send(dp);
										}
										
									}
									
//									if (buffer2.length >= buffer.length){
//										DatagramPacket dp = new DatagramPacket(buffer,
//												buffer.length, InetAddress.getByName(out_Address),
//												out_port);
//										out.send(dp);
//									}else{
//										DatagramPacket dp = new DatagramPacket(buffer2,
//												buffer2.length, InetAddress.getByName(out_Address),
//												out_port);
//										out.send(dp);
//									}
									
								}
							}
							else
							{
								Thread.currentThread();
								try {
									Thread.sleep(40);
								} catch (InterruptedException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
							}
						}
						out.close();
					} catch (IOException e) {
						System.err.println("I/O problems: " + e);
						System.exit(-1);
					}
				}

				
			};
			Thread captureThread = new Thread(runner);
			captureThread.start();
		} catch (LineUnavailableException e) {
			System.err.println("Line unavailable: " + e);
			System.exit(-2);
		}
	}

}
